#include "Matrix.h"
#include"Space.h"
#include"BaseVector.h"

Matrix::Matrix(int m, int n, double values[])
{
	this->m = m;
	this->n = n;
	this->data = Space::CreateDouble(m, n);
	if (values != nullptr)
	{
		this->SetValues(values);
	}
}

Matrix::Matrix(int m, int n, BaseVector vectors[], bool isHorizontals)
{
	this->m = m;
	this->n = n;
	this->data = Space::CreateDouble(m, n);
	this->SetValues(vectors, isHorizontals);
}

Matrix::Matrix(const Matrix & mat) :Matrix(mat.m, mat.n)
{
	double *values = mat.GetValues();
	this->SetValues(values);
	delete[]values;
}


Matrix::~Matrix()
{
	Space::DeleteDouble(this->data, m);
}

void Matrix::SetValues(double values[])
{
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			data[i][j] = values[i*n + j];
		}
	}
}

void Matrix::SetValues(BaseVector vectors[], bool isHorizontal)
{
	if (isHorizontal)
	{
		for (int i = 0; i < m; i++)
		{
			for (int j = 0; j < n; j++)
			{
				data[i][j] = vectors[i].data[j];
			}
		}
	}
	else
	{
		for (int j = 0; j < n; j++)
		{
			for (int i = 0; i < m; i++)
			{
				data[i][j] = vectors[j].data[i];
			}
		}
	}	
}

double * Matrix::GetValues() const
{
	double *res = new double[m*n];
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			res[i*n + j] = data[i][j];
		}
	}
	return res;
}

Matrix Matrix::Transfer()
{
	Matrix res(this->n, this->m);
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			res.data[j][i] = this->data[i][j];
		}
	}
	return res;
}

BaseVector Matrix::ToVector()
{
	double* data = this->GetValues();
	auto vec = BaseVector(this->m * this->n, data);
	delete[] data;
	return vec;
}

Matrix& Matrix::operator=(Matrix& A)
{
	if (this == &A) return *this;
	double* values = A.GetValues();
	this->SetValues(values);
	delete[] values;
	return *this;
}

Matrix operator*(Matrix A, Matrix B)
{
	Matrix C(A.m, B.n);
	for (int i = 0; i < A.m; i++)
	{
		for (int j = 0; j < B.n; j++)
		{
			double s = 0;
			for (int k = 0; k < A.n; k++)
			{
				s += (A.data[i][k] * B.data[k][j]);
			}
			C.data[i][j] = s;
		}
	}
	return C;
}

Matrix operator+(Matrix A, Matrix B)
{
	Matrix C(A.m, A.n);
	for (int i = 0; i < C.m; i++)
	{
		for (int j = 0; j < C.n; j++)
		{
			C.data[i][j] = A.data[i][j] + B.data[i][j];
		}
	}
	return C;
}

Matrix operator+=(Matrix & A, Matrix B)
{
	for (int i = 0; i < A.m; i++)
	{
		for (int j = 0; j < A.n; j++)
		{
			A.data[i][j] += B.data[i][j];
		}
	}
	return A;
}

Matrix operator/(Matrix A, double k)
{
	Matrix C(A.m, A.n);
	for (int i = 0; i < C.m; i++)
	{
		for (int j = 0; j < C.n; j++)
		{
			C.data[i][j] = A.data[i][j] / k;
		}
	}
	return C;
}

Matrix operator/=(Matrix & A, double k)
{
	for (int i = 0; i < A.m; i++)
	{
		for (int j = 0; j < A.n; j++)
		{
			A.data[i][j] /= k;
		}
	}
	return A;
}
